package lex.dm.utils;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.swing.Action;

import org.lex.filter.Filter;
import org.lex.filter.Filters;
import org.lex.utils.MethodNameFormatter;


public class DBMDUtils
{
	public static Action[] getResultSets( Connection con )
	{
		DatabaseMetaData md = null;
		try
		{
			md = con.getMetaData();
		}
		catch( SQLException e1 )
		{
			e1.printStackTrace();
			return new Action[0];
		}
		Filter<Class<?>> f = new ReturnTypeFilter( ResultSet.class );
		Method[] methods = md.getClass().getMethods();
		ArrayList<Action> list = new ArrayList<Action>();
		for( Method m : methods )
		{
			try
			{
				if( 0 == m.getParameterTypes().length && f.accept( m.getReturnType() ) )
				{
					list.add( new ResultSetAction( m, MethodNameFormatter.format(  m.getName() ) ) );
				}
			}
			catch( Exception e )
			{}
		}
		return list.toArray( new Action[0] );
	}

	public static Map<String, String> getMetaData( Connection con )
	{
		DatabaseMetaData md = null;
		try
		{
			md = con.getMetaData();
		}
		catch( SQLException e1 )
		{
			e1.printStackTrace();
			return Collections.emptyMap();
		}
		Object[] empty = new Object[0];
		Filter<Class<?>> f = Filters.not( new ReturnTypeFilter( ResultSet.class ) );
		Method[] methods = md.getClass().getMethods();
		Map<String, String> map = new HashMap<String, String>();
		for( Method m : methods )
		{
			try
			{
				if( 0 == m.getParameterTypes().length && f.accept( m.getReturnType() ) )
				{
					String name = MethodNameFormatter.format( m.getName() );
					map.put( name, String.valueOf( m.invoke( md, empty ) ) );
				}
			}
			catch( Exception e )
			{}
		}
		return map;
	}

	private static class ReturnTypeFilter implements Filter<Class<?>>
	{
		private final Class<?> expect;

		public ReturnTypeFilter( Class<?> expect )
		{
			this.expect = expect;
		}

		@Override
		public boolean accept( Class<?> clz )
		{
			return expect.isAssignableFrom( clz );
		}
	}
}
